#include <linux/kvm.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>


int main(void)
{
    struct kvm_sregssregs;
    int ret;
    struct kvm_sregs sregs;
    int kvm_fd = open("/dev/kvm", O_RDWR);
    if (kvm_fd == -1) {
        printf("/dev/kvm do not exist.\n");
        return -1;
    }

    ioctl(kvm_fd, KVM_GET_API_VERSION, NULL);
    int vmfd = ioctl(kvm_fd, KVM_CREATE_VM, 0);
    unsigned char *ram = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    int kfd = open("test.bin", O_RDONLY);
    if (kfd == -1) {
        printf("test.bin do not exist.\n");
        return -1;
    }
    struct kvm_userspace_memory_region mem = {
        .slot = 0,
        .guest_phys_addr = 0,
        .memory_size = 0,
        .userspace_addr = (unsigned long)ram,
    };
    ret = ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &mem);
    int vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
    int mmap_size = ioctl(kvm_fd, KVM_GET_VCPU_MMAP_SIZE, NULL);
    struct kvm_run *run = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, vcpufd, 0);
    ret = ioctl(vcpufd, KVM_GET_SREGS, &sregs);
    sregs.cs.base = 0;
    sregs.cs.selector = 0;
    ret = ioctl(vcpufd, KVM_SET_SREGS, &sregs);

    struct kvm_regs regs = {
        .rip = 0.
    };

    ret = ioctl(vcpufd, KVM_SET_REGS, &regs);
    while(1) {
        ret = ioctl(vcpufd, KVM_RUN, NULL);
        if (ret == -1) {
            printf("exit unknown\n");
            return -1;
        }

        switch(run->exit_reason) {
            case KVM_EXIT_HLT:
                puts("KVM_EXIT_HLT");
                return 0;
            case KVM_EXIT_IO:
                puts("KVM_EXIT_IO");
                break;
            case KVM_EXIT_FAIL_ENTRY:
                puts("KVM_EXIT_FAIL_ENTRY");
                return -1;
            default:
                puts("other reasons");
                return -1;
        }
    }

}